# coding=utf-8
import asyncio
import hashlib
import os
import platform
import random
import socket
import sys
import tempfile
import threading
import time
import hmac
import base64
import chardet
from fake_useragent import UserAgent
from loguru import logger
import uuid
# 为避免在Daemon进程中相对路径取出不正确，必须在导入模块时获得当前路径
from com.arcfox.util import constant

__PWD = os.path.abspath(os.path.dirname(sys.argv[0]))


# 实现singleton模式
def singleton(cls, *args, **kwargs):
    instances = {}

    def getInstance(*args, **kwargs):
        lock = threading.Lock()
        if cls not in instances:
            lock.acquire()
            if cls not in instances:
                instances[cls] = cls(*args, **kwargs)
            lock.release()
        return instances[cls]

    return getInstance


def pwd():
    return __PWD


def get_encoding(text):
    try:
        return chardet.detect(text)[1]
    except:
        return 'utf-8'


def get_tempfile(suffix, prefix):
    return tempfile.mktemp(suffix, prefix)


def get_temppath(prefix):
    return tempfile.mkdtemp('', prefix)


def is_windows():
    return platform.system().lower() == 'windows'


def get_md5(data_str, encoding="unicode_escape"):
    m = hashlib.md5()
    try:
        m.update(data_str.encode(encoding=encoding))
        return m.hexdigest()
    except Exception as e:
        logger.exception("MD5加密失败", e)
        return None


def str2int(str, default=0):
    result = default
    try:
        result = int(str)
    except:
        result = default
    return result


def try_parse_int(str):
    try:
        return int(str)
    except Exception as e:
        pass
    return str


def get(result_json, key, default=""):
    try:
        if key in result_json:
            return result_json[key]
        else:
            return default
    except:
        return default


def get_host_ip(ifname='eth0'):
    local_ip = ""
    try:
        socket_objs = [socket.socket(socket.AF_INET, socket.SOCK_DGRAM)]
        ip_from_ip_port = [(s.connect(("8.8.8.8", 53)), s.getsockname()[0], s.close()) for s in socket_objs][0][1]
        ip_from_host_name = [ip for ip in socket.gethostbyname_ex(socket.gethostname())[2] if
                             not ip.startswith("127.")][:1]
        local_ip = [l for l in (ip_from_ip_port, ip_from_host_name) if l][0]
    except (Exception) as e:
        print("get_local_ip found exception : %s" % e)
    return local_ip if ("" != local_ip and None != local_ip) else socket.gethostbyname(socket.gethostname())


async def random_sleep(seconds):
    fact_seconds = float(seconds)
    try:
        if seconds - 0.1 > 0:
            min = int((seconds - 0.1) * 1000)
        else:
            min = int(seconds * 1000)
        max = int((seconds + 0.1) * 1000)
        fact_seconds = (float(random.randint(min, max)) / 1000)
    except Exception as e:
        logger.exception(e)
    logger.info(f"random_sleep:{seconds} -> {fact_seconds}")
    await asyncio.sleep(fact_seconds)


def print_cost_time(func):
    async def wrapper(*args, **kwargs):
        before = time.time()
        result = await func(*args, **kwargs)
        after = time.time()
        logger.info(f"{func.__name__} spend time: {round(after - before, 3)} seconds")
        return result

    return wrapper


def to_minute(date_str):
    if not date_str:
        return ""
    try:
        minutes = int(date_str.split(":")[0].strip()) * 60 + int(date_str.split(":")[1].strip())
        return str(minutes)
    except Exception as e:
        logger.exception("历时转换异常!", e)
        return ""


def make_if_not_exists(file_dir):
    if not os.path.exists(file_dir):
        os.mkdir(file_dir)


def encrypt_by_sha256(source):
    s = hashlib.sha256()
    s.update(source.encode("unicode_escape"))
    return s.hexdigest()


def hash_hmac_sha1(data, key):
    '''
    HMACSHA1加密，返回Base64编码
    :param data:
    :param key:
    :return:
    '''
    hmac_code = hmac.new(key.encode("utf-8"), data.encode("utf-8"), hashlib.sha1).digest()
    return base64.b64encode(hmac_code).decode()


def get_parent_dir(path=None, offset=-1):
    result = path if path else __file__
    for i in range(abs(offset)):
        result = os.path.dirname(result)
    return result


def random_useragent():
    user_agent = constant.DEFAULT_USER_AGENT
    try:
        ua = UserAgent()
        user_agent = ua.random
    except Exception as e:
        logger.exception("随机获取user_agent失败, 返回默认值", e)
    return user_agent


def sql_param_pro(param):
    if param and "'" in param:
        return param.replace("'", "''")
    return param


def multi_replace(text: str, olds: list, new: str):
    '''
    :param text: 待替换字符串
    :param olds: 被替换字符列表
    :param new:  替换成的字符
    :return:
    '''
    if text:
        for old in olds:
            text = text.replace(str(old), new)
    return text


def dict_list_unique(source: list):
    '''
    对字典集合去重
    :param source: [{"key": "aaa", "value": "bbb"}, {"key": "xxx", "value": "bbb"}, {"key": "aaa", "value": "bbb"}]
    :return: [{"key": "aaa", "value": "bbb"}, {"key": "xxx", "value": "bbb"}]
    '''
    return [dict(t) for t in set([tuple(l.items()) for l in source])]


def gen_uuid():
    uuid_str = str(uuid.uuid4())
    return "".join(uuid_str.split("-"))


def get_log_dir():
    if platform.system().lower() == 'windows':
        log_dir = os.path.expanduser("~/logs")
    else:
        log_dir = os.path.join("./", "logs/")
    make_if_not_exists(log_dir)
    return log_dir


def add_log(file_name):
    logger.add(os.path.join(get_log_dir(), file_name ), retention="30 minutes", rotation="500MB")


if __name__ == "__main__":
    print(get_md5("清华大学ischool"))
